using System;
using System.Collections.Generic;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Framework.Serialization;
using IQIGame.Onigao.GamePlay;
using LFloatMath.Math;
using NetProtocol.POD;

namespace IQIGame.Onigao.Logic
{
    public static partial class BattleUpdateFactory
    {
        private static Dictionary<Type, EBattleUpdateType> _commandTypes;

        public static BattleUpdatePOD Create(EBattleUpdateType updateType, int executerID, BaseBattleCommand command)
        {
            var rPOD = BattleUpdatePOD.DynamicFactory();
            rPOD.type = (int)updateType;
            rPOD.executerId = executerID;
            rPOD.data = command;
            return rPOD;
        }

        public static BattleUpdatePOD Create()
        {
            return BattleUpdatePOD.DynamicFactory();
        }

        public static void SerializeCommand(object rCmd, SOutputStream rOutput)
        {
            try
            {
                rOutput.Write_byte((sbyte)_commandTypes[rCmd.GetType()]);
                (rCmd as BaseBattleCommand)?.Serialize(rOutput);
            }
            catch (Exception e)
            {
                LogGame.LogError(rCmd + e.ToString() + "\n" + e.StackTrace);
            }
        }

#region 创建与设置UpdateCommand数据

        public static BattleUpdatePOD CreateRound(int roundNum, bool isRoundEnd, List<int> turnQueue)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_Round>();
            rData.roundNum = roundNum;
            rData.isEnd = isRoundEnd;
            rData.turnQueue = turnQueue;

            return Create(EBattleUpdateType.Round, 0, rData);
        }

        public static BattleUpdatePOD CreateTurn(bool isTurnEnd, int executerID, List<int> turnQueue)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_Turn>();
            rData.isEnd = isTurnEnd;
            rData.turnQueue = turnQueue;

            return Create(EBattleUpdateType.Turn, executerID, rData);
        }

        public static BattleUpdatePOD CreatePermitCast(int executerID, int skillID)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_PermitCast>();
            rData.skillID = skillID;

            return Create(EBattleUpdateType.PermitCast, executerID, rData);
        }

        public static BattleUpdatePOD CreateCastSkill(int executerID, int skillID, LVector2 realPos, LVector2 targetPos)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_CastSkill>();
            rData.skillID = skillID;
            rData.realPos = UpdateVector2.Create(realPos);
            rData.targetPos = UpdateVector2.Create(targetPos);

            return Create(EBattleUpdateType.CastSkill, executerID, rData);
        }

        public static BattleUpdatePOD CreateCastSkillComplete(int executerID)
        {
            return Create(EBattleUpdateType.CastSkillComplete, executerID, BaseBattleCommand.Get<BattleCommand_CastSkillComplete>());
        }

        public static BattleUpdatePOD CreateSkillEffective(SkillPart part, int executerID, int index, int responseGUID)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_SkillEffective>();
            rData.part = part.guid;
            rData.index = index;
            rData.responseGUID = responseGUID;

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.SkillEffective;
            rPOD.executerId = executerID;
            rPOD.data = rData;

            return rPOD;
        }

        public static BattleUpdatePOD CreateSkillEffectiveResponse(int executerID, int responseGUID)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_SkillEffectiveResponse>();
            rData.responseGUID = responseGUID;

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.SkillEffectiveResponse;
            rPOD.executerId = executerID;
            rPOD.data = rData;

            return rPOD;
        }

        public static BattleUpdatePOD CreateSkillEffectiveStart(int executerID, int targetID, int responseGUID, long partGUID)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_SkillEffectiveStart>();
            rData.targetID = targetID;
            rData.responseGUID = responseGUID;
            rData.partGUID = partGUID;

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.SkillEffectiveStart;
            rPOD.executerId = executerID;
            rPOD.data = rData;
            return rPOD;
        }

        public static BattleUpdatePOD CreateSkillEffectiveEnd(int executerID, SkillEffectiveResponse resp, int responseGUID)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_SkillEffectiveEnd>();
            rData.data = resp;
            rData.responseGUID = responseGUID;

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.SkillEffectiveEnd;
            rPOD.executerId = executerID;
            rPOD.data = rData;
            return rPOD;
        }

        public static void SetSkillPartData(int executerID, BattleCommand_StartPart data, BattleUpdatePOD pod)
        {
            pod.type = (int)EBattleUpdateType.StartPart;
            pod.executerId = executerID;
            pod.data = data;
        }

        /// <summary>
        /// buff修改
        /// </summary>
        /// <param name="nBuffID"></param>
        /// <param name="nTriggerType">0添加 1移除 2Refresh 3删除</param>
        /// <param name="nTargetID"></param>
        /// <returns></returns>
        public static BattleUpdatePOD CreateBuffChange(BuffHandler rBuff, int nTriggerType, int nTargetID)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_BuffChange>();
            var rBuffData = BuffData.Create(rBuff);
            rData.buff = rBuffData;
            rData.triggerType = nTriggerType;

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.BuffChange;
            rPOD.executerId = nTargetID;
            rPOD.data = rData;

            return rPOD;
        }

        public static BattleUpdatePOD CreateAttrChange(EAttributeType rType, EAttributeAddType rAddType, int nValue, bool bAdd, int nTargetID)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_AttrChange>();
            rData.attrType = (int)rType;
            rData.addType = (int)rAddType;
            rData.value = nValue;
            rData.add = bAdd;

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.AttrChange;
            rPOD.executerId = nTargetID;
            rPOD.data = rData;

            return rPOD;
        }

        public static BattleUpdatePOD CreateUnitPosChange(int nTargetID, LVector2 newPos, LVector2 forward, List<LVector2> path)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_PosChange>();
            rData.pos = UpdateVector2.Create(newPos);
            rData.forward = UpdateVector2.Create(forward);
            if (path != null)
            {
                for (int i = 0; i < path.Count; i++)
                {
                    rData.path.Add(UpdateVector2.Create(path[i]));
                }
            }

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.PosChange;
            rPOD.executerId = nTargetID;
            rPOD.data = rData;

            return rPOD;
        }

        public static BattleUpdatePOD CreateUnitWeaknessPoint(int nTargetID, int nPoint)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_WeaknessPoint>();
            rData.point = nPoint;

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.WeaknessPoint;
            rPOD.executerId = nTargetID;
            rPOD.data = rData;

            return rPOD;
        }

        public static BattleUpdatePOD CreateUnitDead(int nTarget, long nAttacker, bool bRelive)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_Dead>();
            rData.attacker = nAttacker;
            rData.relive = bRelive;

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.Dead;
            rPOD.executerId = nTarget;
            rPOD.data = rData;

            return rPOD;
        }

        public static BattleUpdatePOD CreateUnitBuffDamage(int nTarget, DamageResponse rDamage)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_BuffDamage>();
            rData.damage = rDamage;

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.BuffDamage;
            rPOD.executerId = nTarget;
            rPOD.data = rData;

            return rPOD;
        }

        public static BattleUpdatePOD CreateUnitBuffCure(int nTarget, CureResponse rCure)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_BuffCure>();
            rData.cure = rCure;

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.BuffCure;
            rPOD.executerId = nTarget;
            rPOD.data = rData;

            return rPOD;
        }

        public static BattleUpdatePOD CreateUnitShield(int nTarget, int nCurShield)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_Shield>();
            rData.shield = nCurShield;

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.Shield;
            rPOD.executerId = nTarget;
            rPOD.data = rData;

            return rPOD;
        }

        public static BattleUpdatePOD CreateUnitCustomProperty<T>(int nTarget, int nKey, ETAnyType rType, T rValue)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_CustomProperty>();
            rData.key = nKey;
            rData.valueType = (int)rType;
            rData.value = TAnyHelper.NewAny(rType);
            TAnyHelper.SetAny(rData.value, rValue);

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.CustomProperty;
            rPOD.executerId = nTarget;
            rPOD.data = rData;

            return rPOD;
        }

        public static BattleUpdatePOD CreateAddSkill(int nTarget, bool bAdd, int nSkillID)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_AddSkill>();
            rData.add = bAdd;
            rData.skillID = nSkillID;


            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.AddSkill;
            rPOD.executerId = nTarget;
            rPOD.data = rData;

            return rPOD;
        }

        public static BattleUpdatePOD CreateCharge(Unit executer, int duration, int skillID, SelectParam select, SkillEffectiveData rEffectiveData, string chargePrefab)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_Charge>();
            rData.duration = duration;
            rData.castSkillID = skillID;
            rData.pos = UpdateVector2.Create(select.pos);
            rData.aspect = UpdateVector2.Create(select.aspect);
            rData.curSkill = rEffectiveData.skill.skillID;
            rData.chargePrefab = chargePrefab;
            // 蓄力触发频率不高，先用copy的方法处理bytes数据传输
            ByteBuf buf = ThreadLocalTemporalByteBufPool.Alloc(64);
            SerializeByteBufUtil.SerializeObject(buf, rEffectiveData.effectiveConfig.target);
            rData.targetSelectConfig = buf.CopyData();
            ThreadLocalTemporalByteBufPool.Free(buf);

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.Charge;
            rPOD.executerId = executer.GUID;
            rPOD.data = rData;

            return rPOD;
        }

        public static BattleUpdatePOD CreateChargeStop(Unit executer)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_ChargeStop>();

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.ChargeStop;
            rPOD.executerId = executer.GUID;
            rPOD.data = rData;

            return rPOD;
        }

        public static BattleUpdatePOD CreateMorph(Unit executer, string resName, int entityType, bool active)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_Morph>();
            rData.resName = resName;
            rData.entityType = entityType;
            rData.active = active;

            var rPOD = Create();
            rPOD.type = (int)EBattleUpdateType.Morph;
            rPOD.executerId = executer.GUID;
            rPOD.data = rData;
            return rPOD;
        }

        public static BattleUpdatePOD CreateNextWave(BattleTeamViewPOD nextTeam)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_NextWave>();
            rData.team = nextTeam;

            return Create(EBattleUpdateType.NextWave, 0, rData);
        }

        public static BattleUpdatePOD CreateRemoveUnit(Unit executer)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_RemoveUnit>();
            return Create(EBattleUpdateType.RemoveUnit, executer.GUID, rData);
        }

        public static BattleUpdatePOD CreateSubstitute(int oldUnit, BattleUnitViewPOD subUnit, int nTeam)
        {
            var rData = BaseBattleCommand.Get<BattleCommand_Substitute>();
            rData.subUnit = subUnit;
            rData.teamIndex = nTeam;

            return Create(EBattleUpdateType.Substitute, oldUnit, rData);
        }

#endregion
    }
}